package com.dxy.app.widget.select_num_view;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.BounceInterpolator;
import com.dxy.app.R;
import java.util.ArrayList;
import java.util.List;

/**
 * 描 叙: 帮朋友做的一个选择金额的控件
 * 作 者: duxingyu
 * 时 间: 2017/8/30 17:35
 **/

public class DragProgressView extends View {

  public static final String TAG="TAG_DragProgressView";
  /**
   * 当前选中的区间价位
   * */
  private Shuttle curShuttle;
  /**
   * 每个区间的间距
   * */
  private float shuttleUnitWidth;
  /**
   * 拖拽点的半径
   * */
  private float pointRadius;
  /**
   * 提示文字距离顶部的距离
   * */
  private float startY;
  /**
   * 进度条的起始位置
   * */
  private float offsetStartX;
  /**
   * 进度条拖拽点的当前位置
   * */
  private float offsetX;
  /**
   * 提示文字
   * */
  private String textPromt;
  /**
   * 边框宽度
   * */
  private float strokeWidth =5;
  /**
   * 区间刻度的尺寸,宽\高
   * */
  private float shuttleWidth =4,shuttleHeight =60;
  /**
   * 用于校准操作行为的y轴偏移量
   * */
  private float correctProgressHeight;
  /**
   * 屏幕宽高
   * */
  private float width,height;
  /**
   * 分辨率
   * */
  private float density;
  /**
   * 进度条的高度
   * */
  private float progHeight;
  /**
   * 区间列表
   * */
  private List<Shuttle> shuttleList;
  /**
   * 起始数字，终止数字
   * */
  private int startNum =500,endNum =3000;
  /**
   * 划分为多少个区间
   * */
  private int shuttleCount;
  /**
   * 提示文字的高度
   * */
  private float promptTextHeight;
  /**
   * 选择的字体的高度
   * */
  private float selectTextHeight;
  /**
   * 首字符开始的位置
   * */
  private float charStartX;
  /**
   * 字符串的长度
   * */
  private int charsSize;
  /**
   * 所有数字字符中宽度最大的字符,以此作为标准
   * */
  private float maxCharWidth=0;
  /**
   * 每个区间所在屏幕的宽度
   * */
  private int shutUnitValueDistance;
  /**
   * 最外层有滑动事件的父group
   * */
  private ViewGroup group;
  /**
   * 选中数值的监听器
   * */
  private DragProgressListener listener;
  /**
   * 相关文字的尺寸
   * */
  private float textSizePrompt =40f,//提示信息的字体尺寸
      textSizeSelect=40f,//选择数字的尺寸
      textSizeShuttle=30f;//区间文字尺寸
  /**
   * 相关画笔
   * */
  private Paint paintProg,//绘制进度条的画笔
      paintPoint,//绘制拖拽点的画笔
      paintShuttle,//区间刻度画笔
      textPaint;//绘制文字的画笔
  /**
   * 一些边距
   * */
  private float marginHor,//水平方向上距离两边的距离
      margin_prompt2select=44//我要借款与选择数字之间的间距
      ,margin_select2progress=76//数字与进度条之间的间距
      ,margin_progress2bottom;//进度条到控件底部的间距
  /**
   * 相关颜色资源
   * */
  private int colorProgOutter,//进度条外圈颜色
      colorProgInner,//进度条内圈颜色
      colorSelect,//拖拽点颜色
      colorPrompt,//提示语字体颜色
      colorShuttleText;//区间字体颜色

  
  public DragProgressView(Context context) {
    super(context);
    init(null);
  }

  public DragProgressView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    TypedArray array =context.obtainStyledAttributes(attrs, R.styleable.DragProgressView);
    init(array);
  }

  public DragProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    TypedArray array =context.obtainStyledAttributes(attrs,R.styleable.DragProgressView);
    init(array);
  }

  @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension((int) width, (int) height);
  }
  /**
   * 初始化一些变量
   * */
  private void init(TypedArray array){
    DisplayMetrics metics =getContext().getResources().getDisplayMetrics();
    density =metics.density;
    width =metics.widthPixels;
    if(array!=null){
      colorProgOutter =array.getColor(R.styleable.DragProgressView_drag_progress_outer_color, Color.GREEN);
      colorProgInner =array.getColor(R.styleable.DragProgressView_drag_progress_bar_color, Color.RED);
      colorSelect =array.getColor(R.styleable.DragProgressView_drag_progress_select_color, Color.BLUE);
      colorPrompt =array.getColor(R.styleable.DragProgressView_drag_progress_prompt_text_color,
          Color.BLACK);
      colorShuttleText =array.getColor(R.styleable.DragProgressView_drag_progress_shuttle_text_color,
          Color.GRAY);

      startNum =array.getInt(R.styleable.DragProgressView_drag_progress_start,500);
      endNum =array.getInt(R.styleable.DragProgressView_drag_progress_end,3000);
      textPromt =array.getString(R.styleable.DragProgressView_drag_progress_prompt_text);
      textSizePrompt =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_prompt_text_size,40);
      textSizeShuttle =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_shuttle_text_size,30);
      textSizeSelect =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_select_text_size,45);

      progHeight =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_prog_height,30);
      pointRadius =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_drag_point_radius,50);

      startY =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_top2prompt,44);
      margin_prompt2select =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_prompt2select,44);
      margin_select2progress =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_select2progress,76);
      margin_progress2bottom =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_prog2bottom,132);
      marginHor =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_margin_hor,40);

      shuttleWidth =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_shuttle_width,4);
      shuttleHeight =array.getDimensionPixelSize(R.styleable.DragProgressView_drag_progress_shuttle_height,60);
      shuttleCount =array.getInteger(R.styleable.DragProgressView_drag_progress_shuttle_count,5);

      array.recycle();
    }else{
      colorProgOutter = Color.GREEN;
      colorProgInner = Color.RED;
      colorSelect = Color.BLUE;
      colorPrompt = Color.BLACK;
      colorShuttleText = Color.GRAY;
      startNum =500;
      endNum =3000;
      textPromt="我要借款(元)";
      textSizePrompt =40f;
      textSizeShuttle=30f;

      progHeight =15*density;
      pointRadius =25*density;
      startY =22*density;
      margin_prompt2select =22*density;
      margin_select2progress =38*density;
      margin_progress2bottom =66*density;
      marginHor =20*density;
      shuttleWidth =2*density;
      shuttleHeight =30*density;
      shuttleCount =5;
    }
    int temp =startNum;
    startNum =startNum>endNum?endNum:startNum;
    endNum =startNum>endNum?temp:endNum;

    offsetStartX =offsetX =marginHor+strokeWidth;//进度条的起始位置应该是左边距距离加上边框的宽度
    initShuttles();

    paintPoint =new Paint();
    paintProg =new Paint();
    paintShuttle =new Paint();
    textPaint =new TextPaint();
    initPaint(paintPoint,paintProg,paintShuttle,textPaint);

    float shadowLayerParams =pointRadius/8;
    paintPoint.setShadowLayer(shadowLayerParams*2,0,shadowLayerParams,Color.parseColor("#666666"));
    paintPoint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    setLayerType(LAYER_TYPE_SOFTWARE,paintPoint);//要添加这一句才能显示出阴影

    textPaint.setTextSize(textSizePrompt);
    textPaint.measureText(textPromt);
    promptTextHeight =textPaint.descent()-textPaint.ascent();

    textPaint.setTextSize(textSizeSelect);
    textPaint.measureText(curShuttle.disc+"");
    selectTextHeight =textPaint.descent()-textPaint.ascent();

    String[] stre=new String[]{"0","1","2","3","4","5","6","7","8","9"};
    for(String each:stre){
      float width =textPaint.measureText(each);
      maxCharWidth =width>maxCharWidth?width:maxCharWidth;
    }
    height =startY+margin_prompt2select+margin_select2progress+margin_progress2bottom+promptTextHeight+selectTextHeight;
  }
  /**
   * 初始化区间刻度
   * */
  private void initShuttles(){
    if(shuttleList==null){
      shuttleList =new ArrayList<>();
    }else{
      shuttleList.clear();
      offsetX =offsetStartX;
    }
    float allShuttleWidth =width-marginHor*2-pointRadius*2;
    shuttleUnitWidth =allShuttleWidth/shuttleCount;
    shutUnitValueDistance =(endNum-startNum)/shuttleCount;
    for(int i=0;i<=shuttleCount;i++){
      Shuttle shuttle =new Shuttle();
      shuttle.offsetPosX =marginHor+pointRadius+shuttleUnitWidth*i;
      if(i==shuttleCount){
        shuttle.disc =endNum;
      }else{
        shuttle.disc =startNum+shutUnitValueDistance*i;
      }
      shuttleList.add(shuttle);
    }
    curShuttle =new Shuttle(shuttleList.get(0).offsetPosX,shuttleList.get(0).disc);
  }

  private void initPaint(Paint...paints){
    for(Paint each:paints){
      each.setAntiAlias(true);
      each.setStrokeCap(Paint.Cap.ROUND);
      each.setStrokeWidth(strokeWidth);
    }
  }

  @Override protected void onDraw(Canvas canvas) {
    float tempY =startY;
    textPaint.setTextSize(textSizePrompt);
    textPaint.setColor(colorPrompt);
    float promtWidth =textPaint.measureText(textPromt);
    canvas.drawText(textPromt,(width-promtWidth)/2, tempY-textPaint.ascent(),textPaint);
    tempY +=margin_prompt2select+promptTextHeight;

    drawSelectNum(canvas,tempY,curShuttle.disc+"");
    tempY+=margin_select2progress+selectTextHeight;

    RectF rProgressDef =new RectF(marginHor, tempY,width-marginHor, tempY +progHeight);
    correctProgressHeight =tempY+progHeight/2;
    paintProg.setColor(colorProgOutter);
    paintProg.setStyle(Paint.Style.STROKE);
    paintProg.setStrokeWidth(strokeWidth);
    canvas.drawRoundRect(rProgressDef,progHeight/2,progHeight/2,paintProg);

    RectF rProgress =new RectF(offsetStartX, tempY +strokeWidth,offsetX, tempY +progHeight-strokeWidth);
    paintProg.setColor(colorProgInner);
    paintProg.setStyle(Paint.Style.FILL);
    canvas.drawRoundRect(rProgress,(progHeight-strokeWidth*2)/2,(progHeight-strokeWidth*2)/2,paintProg);

    paintPoint.setColor(colorSelect);
    canvas.drawCircle(offsetX, tempY +progHeight/2,pointRadius,paintPoint);
    tempY =rProgressDef.bottom+pointRadius;

    paintShuttle.setColor(colorShuttleText);
    for(int i=0;i<shuttleList.size();i++){
      Shuttle shuttle =shuttleList.get(i);
      float offsetX =shuttle.offsetPosX;
      RectF r =new RectF(offsetX-shuttleWidth/2,tempY,offsetX+shuttleWidth/2,tempY+shuttleHeight);
      canvas.drawRect(r,paintShuttle);
    }
    tempY+=shuttleHeight;
    textPaint.setColor(colorShuttleText);
    textPaint.setTextSize(textSizeShuttle);
    float startWidth =textPaint.measureText(startNum+"");
    canvas.drawText(startNum+"",shuttleList.get(0).offsetPosX-startWidth/2,tempY+shuttleHeight-textPaint.ascent(),textPaint);
    float endWidth =textPaint.measureText(endNum+"");
    canvas.drawText(endNum+"",shuttleList.get(shuttleList.size()-1).offsetPosX-endWidth/2,tempY+shuttleHeight-textPaint.ascent(),textPaint);
  }
  /**
   * 处理数字跳动时抖动的情况
   * */
  private void drawSelectNum(Canvas canvase,float delY,String select){
    textPaint.setColor(colorSelect);
    textPaint.setTextSize(textSizeSelect);
    textPaint.measureText(select);
    String[] arr =select.split("");
    if(charsSize!=arr.length){//
      float charsTotalLength =maxCharWidth*arr.length;//最大宽度
      charStartX =(width-charsTotalLength)/2-maxCharWidth/2;
      charsSize =arr.length;
    }
    for(int i=0;i<arr.length;i++){
      canvase.drawText(arr[i],charStartX+i*maxCharWidth,delY-textPaint.ascent(),textPaint);
    }
  }
  @Override public boolean onTouchEvent(MotionEvent event) {
    float delX;
    switch (event.getAction()){
      case MotionEvent.ACTION_DOWN:
        delX =event.getRawX();
        float y =event.getY();//y轴方向上要去相对距离
        if(delX<offsetX-2*pointRadius||delX>offsetX+2*pointRadius||y< correctProgressHeight -2*progHeight||y>
            correctProgressHeight
                +2*progHeight){
          return super.onTouchEvent(event);
        }
        if(group!=null){
          group.requestDisallowInterceptTouchEvent(true);
        }
        break;
      case MotionEvent.ACTION_MOVE:
        delX =event.getRawX();
        if(delX>offsetStartX&&delX<width-offsetStartX){
          offsetX =delX;
          invalidate();
        }
        break;
      case MotionEvent.ACTION_UP:
        offsetX =event.getRawX();
        Shuttle shuttle =getNeareastOffsetX(offsetX);
        if(listener!=null){
          listener.curSelectShuttle(shuttle.disc);
        }
        autoNearBy(shuttle,300);
        curShuttle.disc =shuttle.disc;
        curShuttle.offsetPosX =shuttle.offsetPosX;
        break;
    }
    return true;
  }
  /**
   * 设置提示文字
   * */
  public void setTextPromt(String textPromt){
    this.textPromt =textPromt;
    invalidate();
  }
  /**
   * 设置起始数字
   * */
  public void setStartAndEndNum(int start,int end,int shuttleCount){
    this.startNum=start<end?start:end;
    this.endNum =start<end?end:start;
    this.shuttleCount =shuttleCount;
    Shuttle shuttle =new Shuttle(marginHor+pointRadius,startNum);
    autoNearBy(shuttle,600);
    initShuttles();
    shuttleList.get(0).disc =shuttle.disc;
  }
  /**
   * 偏移归零
   * */
  private void autoNearBy(final Shuttle shuttle,long duration){
    float closeToShuttleOffsetX =shuttle.offsetPosX;
    final float distance =closeToShuttleOffsetX -offsetX;
    final float tempOffsetX =offsetX;

    final int distanceNum =shuttle.disc-curShuttle.disc;
    final int curDisc =curShuttle.disc;
    ValueAnimator ani =new ValueAnimator();
    ani.setInterpolator(new BounceInterpolator());
    ani.setFloatValues(0,1);
    ani.addUpdateListener((valueAnimator)->{
      float density = (float) valueAnimator.getAnimatedValue();
      offsetX =tempOffsetX+distance*density;
      curShuttle.disc = (int) (curDisc+distanceNum*density);
      if(Math.abs(curShuttle.disc-shuttle.disc)<shutUnitValueDistance/50){//被除数不能超过50，避免出现四舍五入上的误差，导致显示数字出现偏差。
        curShuttle.disc =shuttle.disc;
      }
      invalidate();
    });
    ani.setDuration(duration);
    ani.start();

  }
  /**
   * 获取最近的区间刻度
   * */
  private Shuttle getNeareastOffsetX(float x){
    for(Shuttle each:shuttleList){
      if(Math.abs(x-each.offsetPosX)<shuttleUnitWidth/2){
        return each;
      }
    }
    return shuttleList.get(0);
  }
  /**
   * 将该父group设置进来
   * */
  public void setOutEventGroup(ViewGroup group){
    this.group =group;
  }
  /**
   * 当前选中的区间刻度
   * */
  public void setListener(DragProgressListener listener){
    this.listener =listener;
    listener.curSelectShuttle(curShuttle.disc);//一旦设置了监听，就立刻将当前值返回，用于处理用户没有选择价格时的无返回值的问题。
  }
  public interface DragProgressListener{
    void curSelectShuttle(int price);
  }

  public static class Shuttle{
    public float offsetPosX;
    public int disc;

    public Shuttle(){
    }
    public Shuttle(float offsetStartX,int disc){
      this.offsetPosX =offsetStartX;
      this.disc =disc;
    }

    @Override public String toString() {
      return "Shuttle{" + "offsetPosX=" + offsetPosX + ", disc=" + disc + '}';
    }
  }
}
